import java.net.*;
import java.io.*;
import java.util.*;

class LoginHui extends Thread {
    Socket sock;
    BroadcasterHui bc;

    List<String> userList = Arrays.asList("peter", "hui", "cindy", "xiaoyu");

    LoginHui(Socket _sock, BroadcasterHui _bc) {
        sock = _sock;
        bc = _bc;
    }

    public void run() {
        InputStream in;
        OutputStream out;
        byte [] byteList = new byte[100];
        int n;
        String user;

        try {
            in = sock.getInputStream();
            out = sock.getOutputStream();
        }catch (Exception e){
            System.err.println("Login.run: " + e);
            return;
        }

        try {
            n = in.read(byteList);
            
            user = (new String(byteList, 0, n)).trim();
            System.out.println("INPUT user=[" + user + "]");
            
            for(String u : userList){
                if (u.equals(user)){
                    bc.add(sock, user);
                    return;
                }
            }
            
            out.write("ERROR user not found\n".getBytes());
            out.flush();
            sock.close();

        }catch (Exception e){
            System.err.println("ERROR Login.run ex: " + e);
        }

        System.out.println("Login thread stop");

    }

}
class ConnHui extends Thread {
    Socket sock;
    InputStream in;
    OutputStream out;
    BroadcasterHui bc;
    String user = "_BUG_";

    ConnHui(Socket _sock, BroadcasterHui _bc, String _user){
        sock = _sock;
        user = _user;
        bc = _bc;
        try{
            in = sock.getInputStream();
            out = sock.getOutputStream();
        }catch(Exception e){
            System.err.println("ConnHui.inout " + e);
        }
    }
    
    public void close() {
        try{
            if (in != null) {
                in.close();
                in = null;
            }
            if(out != null) {
                out.close();
                out = null;
            }
            if(sock != null) {
                sock.close();
                sock = null;
            }
        } catch (Exception e) {
            System.err.println("ConnHui.close " + e);
        }
        sock = null;
        in = null;
        out = null;
    }

    public void run() {
        byte[] byteList = new byte[100];
        int n = 0;
        int success = 0;
        final byte[] userByte = (user + ":").getBytes();


        try{
            while((n = in.read(byteList)) > 0){
                byte[] list = new byte[userByte.length + n];
                System.arraycopy(userByte, 0, list, 0, userByte.length);
                System.arraycopy(byteList, 0, list, userByte.length, n);

                success = bc.sendAll(list, 0, list.length);
                System.out.println("Success sendAll = " + success);
            }
        }catch (Exception e){
            System.err.println("ConnHui.run " + e);
        }
        close();
    }
}



class BroadcasterHui extends Thread {
    boolean running = true;
    ServerSocket sssSock = null;
    ArrayList<ConnHui> connList = new ArrayList<ConnHui>();
    
    BroadcasterHui(ServerSocket _sssSock) {
        sssSock = _sssSock;
    }

    public void run(){
        Socket cSock = null;
        LoginHui login;
        while (running) {
            try {
                cSock = sssSock.accept();
                System.out.println("accept");
                login = new LoginHui(cSock, this);
                login.start();
            } catch (Exception e) {
                System.err.println("Broadcaster.run ex: " + e);
                break;
            }
        }
    }

    public int sendAll(byte[] byteList, int offset, int count) {
        int success = 0;
        Iterator<ConnHui> it = connList.iterator();

        while (it.hasNext()) {
            ConnHui c = it.next();
            try{
                if(c.out == null){
                    c.close();
                    it.remove();
                    continue;
                }
                c.out.write(byteList, offset, count);
                success ++;
            } catch (Exception e) {
                System.err.println("sendAll ex: " + e);
                c.close();
                it.remove();
            }
        }
        return success;
    }

    public void add(Socket sock, String user){
        ConnHui c = null;
        Iterator<ConnHui> it = connList.iterator();
        while (it.hasNext()) {
            c = it.next();
            if (user.equals(c.user)) {
                c.close(); // close the connection
                it.remove();
            }
        }
        
        try {
            c = new ConnHui(sock, this, user);    
        }catch(Exception e){
            System.err.println("add sock ex: " + e);
            return;
        }
        connList.add(c);
        c.start();
    }
}


public class ServerHui {
    public static void main(String arg[]) throws Exception
    {
        System.out.println("---- ServerHui start v3 ----");
        ServerSocket sssSock = null;

        InetAddress address = InetAddress.getByName("0.0.0.0");
        sssSock = new ServerSocket(7749,10, address);

        BroadcasterHui bc = new BroadcasterHui(sssSock);
        bc.start();

    }
}


